package com.demo.service.riot;

import com.demo.config.RiotConfig;
import com.demo.entity.riot.MatchInfo;
import com.demo.entity.riot.Summoner;
import com.demo.exception.ApiException;
import com.demo.mapper.riot.SummonerMapper;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class SummonerService {

    private final RiotBasicService riotBasicService;
    private final RiotConfig riotConfig;

    private static final String ACCOUNT_BY_RIOT_ID = "/riot/account/v1/accounts/by-riot-id/{gameName}/{tagLine}";
    private static final String ACCOUNT_BY_PUUID = "/riot/account/v1/accounts/by-puuid/{puuid}";
    private static final String SUMMONER_BY_PUUID = "/lol/summoner/v4/summoners/by-puuid/{puuid}";

    @Resource
    private SummonerMapper summonerMapper;

    public SummonerService(RiotBasicService riotBasicService, RiotConfig riotConfig) {
        this.riotBasicService = riotBasicService;
        this.riotConfig = riotConfig;
    }

    private String getPuuidByDB(String serverRegion, String gameName, String tagLine)
    {
        return summonerMapper.getPuuidByName(serverRegion,gameName, tagLine);
    }

    private String getPuuidByApi(String serverRegion, String gameName, String tagLine) throws ApiException {
        Map<String,String> pathParams = new HashMap<>();
        pathParams.put("gameName", gameName);
        pathParams.put("tagLine", tagLine);
        String puuid = riotBasicService.getJsonByParams(riotConfig, pathParams, null, serverRegion, ACCOUNT_BY_RIOT_ID, "账号", false).get("puuid").asText();
        return puuid;
    }

    private Boolean shouldUpdateSummonerInfo(String puuid, String serverRegion) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime lastUpdate = summonerMapper.getLastUpdate(serverRegion, puuid);
        Duration duration = Duration.between(lastUpdate, now);
        return duration.toHours() > 24 * 3;
    }

    public Summoner createSummoner(Summoner summoner) throws ApiException {
        summonerMapper.insertSummoner(summoner);
        summonerMapper.insertSummonerInfo(summoner);
        return summoner;
    }

    private void updateSummoner(Summoner summoner) {
        summonerMapper.updateSummonerInfo(summoner);
    }

    public void updateSummoner(String serverRegion, String puuid) throws ApiException {
        Map<String,String> pathParams = new HashMap<>();
        pathParams.put("puuid", puuid);
        JsonNode accountInfo = riotBasicService.getJsonByParams(riotConfig, pathParams, null, serverRegion, ACCOUNT_BY_PUUID, "账号", false);
        Summoner summoner = getSummonerByApi(serverRegion, puuid, accountInfo.get("gameName").asText(), accountInfo.get("tagLine").asText());
        updateSummoner(summoner);
    }

    public List<Summoner> getSummonerByMatchInfo(MatchInfo matchInfo) throws ApiException {
        List<Summoner> summoners = matchInfo.toSummoners();
        for(Summoner summoner : summoners) {
            if(getSummonerByDB(summoner.getServerRegion(), summoner.getPuuid()) != null) {
                LocalDateTime updateTime = Instant.ofEpochMilli(matchInfo.getGameCreation()).atZone(ZoneId.systemDefault()).toLocalDateTime();
                LocalDateTime lastUpdate = summonerMapper.getLastUpdate(summoner.getServerRegion(), summoner.getPuuid());
                if(lastUpdate.isBefore(updateTime)) {
                    updateSummoner(summoner);
                }
            } else {
                createSummoner(summoner);
            }
        }
        return summoners;
    }

    private Summoner getSummonerByDB(String serverRegion, String puuid){
        return summonerMapper.getSummonerByPuuid(puuid, serverRegion);
    }

    private Summoner getSummonerByApi(String serverRegion, String puuid, String gameName, String tagLine) throws ApiException {
        Map<String,String> pathParams = new HashMap<>();
        pathParams.put("puuid", puuid);
        JsonNode summonerInfo = riotBasicService.getJsonByParams(riotConfig, pathParams, null, serverRegion, SUMMONER_BY_PUUID, "召唤师", true);
        Summoner summoner = new Summoner(
                puuid,
                RegionTransfer.getRegion(serverRegion),
                serverRegion,
                gameName,
                tagLine,
                summonerInfo.get("profileIconId").asText(),
                summonerInfo.get("summonerLevel").asInt()
        );
        return summoner;
    }

    public Summoner getSummonerByName(String serverRegion, String gameName, String tagLine) throws ApiException {
        String puuid = getPuuidByDB(serverRegion, gameName, tagLine);
        Summoner summoner;
        if(puuid == null) {
            //改名检测
            puuid = getPuuidByApi(serverRegion, gameName, tagLine);
            summoner = getSummonerByApi(serverRegion, puuid, gameName, tagLine);
            if(summonerMapper.hasSummoner(serverRegion, puuid)) {
                //由于改名需要强制更新
                updateSummoner(summoner);
            } else {
                createSummoner(summoner);
            }
        } else{
            if(shouldUpdateSummonerInfo(puuid, serverRegion)) {
                summoner = getSummonerByApi(serverRegion, puuid, gameName, tagLine);
                updateSummoner(summoner);
            } else {
                summoner = getSummonerByDB(serverRegion, puuid);
            }
        }
        return summoner;
    }

    public Summoner getSummonerByPuuid(String serverRegion, String puuid) throws ApiException {
        if(summonerMapper.hasSummoner(serverRegion, puuid)) {
            if(shouldUpdateSummonerInfo(puuid, serverRegion)) {
                Map<String,String> pathParams = new HashMap<>();
                pathParams.put("puuid", puuid);
                JsonNode accountInfo = riotBasicService.getJsonByParams(riotConfig, pathParams, null, serverRegion, ACCOUNT_BY_PUUID, "账号", false);
                Summoner summoner = getSummonerByApi(serverRegion, puuid, accountInfo.get("gameName").asText(), accountInfo.get("tagLine").asText());
                updateSummoner(summoner);
                return summoner;
            } else{
                return getSummonerByDB(serverRegion, puuid);
            }
        } else {
            Map<String,String> pathParams = new HashMap<>();
            pathParams.put("puuid", puuid);
            JsonNode accountInfo = riotBasicService.getJsonByParams(riotConfig, pathParams, null, serverRegion, ACCOUNT_BY_PUUID, "账号", false);
            Summoner summoner = getSummonerByApi(serverRegion, puuid, accountInfo.get("gameName").asText(), accountInfo.get("tagLine").asText());
            createSummoner(summoner);
            return summoner;
        }
    }

    public long getUpdateDuration(String serverRegion, String puuid) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime lastUpdate = summonerMapper.getLastUpdate(serverRegion, puuid);
        Duration duration = Duration.between(lastUpdate, now);
        return duration.toHours();
    }
}
